import { _decorator, BoxCollider2D, Collider2D, Color, Component, Contact2DType, Graphics, Node, RigidBody2D, Size, Sprite, UITransform, Vec2, Vec3, view } from 'cc';
import { MapSpawner } from '../Entity/MapSpawner';
import { Unit } from '../Entity/Unit';
import GameEventMgr, { GameEvent } from '../Model/GameEventMgr';
import { Global, UnitType } from '../Util/Global';
import { UICtrl } from './UICtrl';
import { GameStickerType } from '../Model/GameStickerMgr';

const { ccclass, property } = _decorator;
enum BlockEnum {
    None,
    LeftTop,
    RightTop,
    LeftBottom,
    RightBottom,
}

@ccclass('MapCtrl')
export class MapCtrl extends Component {

    @property([Node])
    mapBg: Node[] = [];
    @property(Unit)
    player: Unit = null;
    @property(RigidBody2D)
    rigidbody: RigidBody2D = null;
    @property(BoxCollider2D)
    collider: BoxCollider2D = null;

    @property(MapSpawner)
    mapSpawner: MapSpawner = null;

    mapBgPos: Vec3 = new Vec3();//区块小地图的位置 
    playerPos: Vec3 = new Vec3();

    currentMapBg: Node = null;

    blockWidth = 0;//地图实例（区块）宽一半
    blockHeight = 0;

    playerBlockPos = BlockEnum.None;
    mapCenterPos: Vec3 = new Vec3();//大地图中心位置 

    mapUnits: Unit[] = [];
    get unitCountInMap() {
        return this.mapUnits.length;
    }

    get unitsInMap() {

        let units: Unit[] = [];
        for (let i = 0; i < this.mapUnits.length; i++) {
            let u = this.mapUnits[i];
            if (u && !u.death) {
                units.push(this.mapUnits[i]);
            }
        }

        this.mapUnits = units;

        return units;
    }

    graphics: Graphics = null;

    drawMapBlock(isShow: boolean = true) {
        //绘制地图区域分界
        this.graphics.clear();
        if (isShow) {
            this.graphics.lineWidth = 2;
            this.graphics.strokeColor = Color.GREEN;
            this.graphics.rect(0, 0, this.blockWidth * 2, this.blockHeight * 2);
            this.graphics.rect(-this.blockWidth * 2, 0, this.blockWidth * 2, this.blockHeight * 2);
            this.graphics.rect(-this.blockWidth * 2, -this.blockHeight * 2, this.blockWidth * 2, this.blockHeight * 2);
            this.graphics.rect(0, -this.blockHeight * 2, this.blockWidth * 2, this.blockHeight * 2);
            this.graphics.stroke();
        }
    }

    protected onEnable(): void {

        this.currentMapBg = this.mapBg[0];
        let tran = this.currentMapBg.getComponent(UITransform);
        let coverNodeSize = tran.contentSize;

        this.blockWidth = coverNodeSize.width / 2;
        this.blockHeight = coverNodeSize.height / 2;

        this.collider.on(Contact2DType.BEGIN_CONTACT, this.onTriggerEnter, this);
        this.collider.on(Contact2DType.END_CONTACT, this.onTriggerExit, this);

        this.collider.size = new Size(coverNodeSize.width * 2, coverNodeSize.height * 2);
        this.collider.offset = Vec2.ZERO.clone();

        this.graphics = this.node.getComponent(Graphics);

        // this.drawMapBlock();

        this.mapSpawner.mapCtrl = this;

        GameEventMgr.Register(this, GameEvent.UnitDestroy, this.unitDestroyEventMapHandler.bind(this));
        GameEventMgr.Register(this, GameEvent.OnPlanetNoGravityInpact, this.planetDismissGravityEventHandler.bind(this));
        // GameEventMgr.Register(this, GameEvent.PlayerDestroy, this.ResetMapData.bind(this));
        GameEventMgr.Register(this, GameEvent.GameReset, this.ResetMapData.bind(this));
        GameEventMgr.Register(this, GameEvent.GameStart, this.RefreshTracker.bind(this));
    }

    protected onDisable(): void {
        GameEventMgr.UnRegister(this, GameEvent.UnitDestroy);
        GameEventMgr.UnRegister(this, GameEvent.OnPlanetNoGravityInpact);
        GameEventMgr.UnRegister(this, GameEvent.GameStart);
    }

    RefreshTracker() {

        this.playerBlockPos = BlockEnum.None;
        this.unitsInMap.forEach(v => {
            UICtrl.ClearStickerRenderer(v, GameStickerType.Tracker);
            UICtrl.CreateStickerRenderer(v, GameStickerType.Tracker);
        });
    }

    ResetMapData() {
        this.currentMapBg = this.mapBg[0];
        if (this.player && !this.player.death) {
            this.currentMapBg.setWorldPosition(this.player.unitWorldPos);
            this.CheckBlock();
        }
        this.playerBlockPos = BlockEnum.None;
        this.UpdateMapPos();//刷新地图位置
    }

    //有单位销毁
    protected unitDestroyEventMapHandler(unit: Unit, reason: string) {
        if (unit && unit.unitType > UnitType.UnitSpacecra) {
            let indexToRemove = this.mapUnits.indexOf(unit);
            if (indexToRemove !== -1) {
                this.mapUnits.splice(indexToRemove, 1);
            }

            // for (let i = 0; i < unit.uChildren.length; i++) {
            //     let ch = unit.uChildren[i];
            //     if (!this.mapUnits.includes(ch)) {
            //         ch.DestroySelf("父级销毁，且脱离区域！");
            //     }
            // }

            UICtrl.Instance.UpdateMapInfo();
        }
    }

    //有行星孤立
    protected planetDismissGravityEventHandler(unit: Unit) {
        if (!this.CheckUnitIncluded(unit)) {
            unit.DestroySelf("脱离区域！");
        }
    }

    update(dt: number) {
        this.mapSpawner.RandomSpawnUnitCD(1);
        if (this.player && !this.player.death) {
            this.CheckMap();
        }
    }

    /**检测玩家并刷新地图信息 */
    CheckMap() {
        if (this.currentMapBg != null) {

            // this.mapSpawner.RandomSpawnUnitCD(1);

            if (!this.CheckBlock()) {
                //玩家在地图的所在的区域变化
                this.UpdateMapPos();//刷新地图位置
                this.mapSpawner.RandomSpawnUnitImmediately();
                let otherMap: Node[] = [];
                for (let i = 0; i < this.mapBg.length; i++) {
                    if (this.currentMapBg != this.mapBg[i]) {
                        otherMap.push(this.mapBg[i]);
                    }
                }

                // let ranMap = otherMap[Math.floor(Math.random() * (this.mapBg.length - 1))];

                // this.mapSpawner.spawnBaseNode = ranMap;
                // this.mapSpawner.RandomSpawnUnit();
            }

            if (this.playerBlockPos == BlockEnum.None) {
                //不在任何地图以及地图区域
                let inside = false;
                this.mapBg.forEach(map => {
                    this.CheckBlock(map);
                    if (this.playerBlockPos != BlockEnum.None) {
                        this.currentMapBg = map;//当前所在地图
                        // this.mapSpawner.spawnBaseNode = this.currentMapBg;
                        inside = true;
                    }
                });
                if (!inside) {
                    GameEventMgr.Dispatch(GameEvent.LogGameMessage, "玩家不在地图范围!!!");
                    this.ResetMapData();
                }
            }
        }

    }

    /**
     * 检测玩家刷新区块定位
     * @return 是否没更换区块
     */
    CheckBlock(map?: Node): boolean {
        if (map) {
            map.getPosition(this.mapBgPos);
        }
        else {
            this.currentMapBg.getPosition(this.mapBgPos);
        }

        this.player.node.getPosition(this.playerPos);
        this.playerPos.subtract(this.mapBgPos);

        let beforePos = this.playerBlockPos;

        if (Math.abs(this.playerPos.x) < this.blockWidth && Math.abs(this.playerPos.y) < this.blockHeight) {
            // 玩家节点在覆盖区域内部
            if (this.playerPos.x <= 0 && this.playerPos.y >= 0) {
                // 左上区块
                this.playerBlockPos = BlockEnum.LeftTop;
            } else if (this.playerPos.x > 0 && this.playerPos.y > 0) {
                // 右上区块
                this.playerBlockPos = BlockEnum.RightTop;
            } else if (this.playerPos.x < 0 && this.playerPos.y < 0) {
                // 左下区块
                this.playerBlockPos = BlockEnum.LeftBottom;
            } else if (this.playerPos.x > 0 && this.playerPos.y < 0) {
                // 右下区块
                this.playerBlockPos = BlockEnum.RightBottom;
            }
        }
        else {
            this.playerBlockPos = BlockEnum.None;
        }

        return beforePos == this.playerBlockPos;
    }

    UpdateMapPos() {

        let changeMap: Node[] = [];
        this.mapBg.forEach(map => { if (map != this.currentMapBg) changeMap.push(map); });

        this.currentMapBg.getWorldPosition(this.mapCenterPos);
        Global.GameNodeTran.convertToNodeSpaceAR(this.mapCenterPos, this.mapCenterPos);

        switch (this.playerBlockPos) {
            case BlockEnum.LeftTop:
                changeMap[0].setPosition(this.mapBgPos.x - this.blockWidth * 2, this.mapBgPos.y);
                changeMap[1].setPosition(this.mapBgPos.x - this.blockWidth * 2, this.mapBgPos.y + this.blockHeight * 2);
                changeMap[2].setPosition(this.mapBgPos.x, this.mapBgPos.y + this.blockHeight * 2);
                this.mapCenterPos.x -= this.blockWidth;
                this.mapCenterPos.y += this.blockHeight;
                break;
            case BlockEnum.RightTop:
                changeMap[0].setPosition(this.mapBgPos.x + this.blockWidth * 2, this.mapBgPos.y);
                changeMap[1].setPosition(this.mapBgPos.x + this.blockWidth * 2, this.mapBgPos.y + this.blockHeight * 2);
                changeMap[2].setPosition(this.mapBgPos.x, this.mapBgPos.y + this.blockHeight * 2);
                this.mapCenterPos.x += this.blockWidth;
                this.mapCenterPos.y += this.blockHeight;
                break;
            case BlockEnum.LeftBottom:
                changeMap[0].setPosition(this.mapBgPos.x - this.blockWidth * 2, this.mapBgPos.y);
                changeMap[1].setPosition(this.mapBgPos.x - this.blockWidth * 2, this.mapBgPos.y - this.blockHeight * 2);
                changeMap[2].setPosition(this.mapBgPos.x, this.mapBgPos.y - this.blockHeight * 2);
                this.mapCenterPos.x -= this.blockWidth;
                this.mapCenterPos.y -= this.blockHeight;
                break;
            case BlockEnum.RightBottom:
                changeMap[0].setPosition(this.mapBgPos.x + this.blockWidth * 2, this.mapBgPos.y);
                changeMap[1].setPosition(this.mapBgPos.x + this.blockWidth * 2, this.mapBgPos.y - this.blockHeight * 2);
                changeMap[2].setPosition(this.mapBgPos.x, this.mapBgPos.y - this.blockHeight * 2);
                this.mapCenterPos.x += this.blockWidth;
                this.mapCenterPos.y -= this.blockHeight;
                break;
        }

        if (this.playerBlockPos != BlockEnum.None) {
            // console.log("地图位置更新：" + this.mapCenterPos);
            this.node.setPosition(this.mapCenterPos);
        }
    }

    public CreateSticker_AllUnitInScreen(type: GameStickerType, createdHandler?: (node: Node) => void, interval: number = 0) {
        this.mapUnits.forEach((unit: Unit, index: number) => {
            if (unit.isInScreenPos) {
                if (interval > 0) {
                    this.scheduleOnce(() => {
                        let sticker = UICtrl.CreateStickerRenderer(unit, type);
                        createdHandler && createdHandler(sticker);
                    }, interval * index);
                }
                else {
                    let sticker = UICtrl.CreateStickerRenderer(unit, type);
                    createdHandler && createdHandler(sticker);
                }
            }
        });
    }

    public ClearSticker_AllUnit(type: GameStickerType) {
        this.mapUnits.forEach((unit: Unit) => {
            UICtrl.ClearStickerRenderer(unit, type);
        });
    }

    protected onTriggerEnter(selfCollider: Collider2D, otherCollider: Collider2D) {
        let other = otherCollider.node.getComponent(Unit);

        if (other && other.unitType >= UnitType.UnitAsteroid) {
            this.scheduleOnce(() => {
                UICtrl.CreateStickerRenderer(other, GameStickerType.Tracker);
            })
            if (!this.CheckUnitIncluded(other)) {
                this.mapUnits.push(other);
                UICtrl.Instance.UpdateMapInfo();
            }

            other.deathTime = -1;
            // console.log("进入区域：" + other.node.getSiblingIndex());
        }
    }

    protected onTriggerExit(selfCollider: Collider2D, otherCollider: Collider2D) {

        let other = otherCollider.node.getComponent(Unit);

        if (other && other.unitType >= UnitType.UnitAsteroid) {
            // UICtrl.ClearStickerRenderer(other, GameStickerType.Tracker);
            let indexToRemove = this.mapUnits.indexOf(other);
            if (indexToRemove !== -1) {
                this.mapUnits.splice(indexToRemove, 1);
                UICtrl.Instance.UpdateMapInfo();
            }

            if (!other.parentUnit || other.parentUnit == other) {
                //无父级
                other.deathTime = 5;
                // console.log("离开区域：" + other.node.getSiblingIndex());
            }
            else if (!this.CheckUnitIncluded(other.parentUnit)) {
                //父级也不在区域内
                other.deathTime = 5;
            }
        }
    }

    CheckUnitIncluded(unit: Unit): boolean {
        return this.mapUnits.indexOf(unit) !== -1;
    }
}


